﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ChartOO
{
    /// <summary>
    /// PieChart.xaml 的交互逻辑
    /// </summary>
    public partial class PieChart : UserControl
    {
        private Point _arcStartPoint; //圆弧开始位置
        private double _angle;//最后一个扇形对应的角度
        private double _totalValue;//数据之和

        public PieChart()
        {
            InitializeComponent();
            this.Loaded += PieChart_Loaded;
        }

        private void Refresh()
        {
            this.chartTitle.Text = this.ChartTitle;
            this.InitInfoList(this.ItemsSource, out _totalValue);
            this.DrawSector();
            this.legendList.ItemsSource = this.InfoList;
        }

        private void PieChart_Loaded(object sender, RoutedEventArgs e)
        {
            this.Refresh();
        }

        private void DrawArc(double value, SolidColorBrush color)
        {
            Path path = new Path();
            path.Fill = color;

            PathGeometry pathGeometry = new PathGeometry();
            path.Data = pathGeometry;
            path.ToolTip = value;

            PathFigure pathFigure = new PathFigure();
            pathFigure.StartPoint = new Point(this.Radious, this.Radious);
            pathFigure.Segments.Add(new LineSegment { Point = _arcStartPoint });

            bool isLargeArc;
            Point arcEndPoint = this.CalulateArcEndPoint(value, _totalValue, out isLargeArc);
            pathFigure.Segments.Add(new ArcSegment { Point = arcEndPoint, Size = new Size(this.Radious, this.Radious), SweepDirection = SweepDirection.Counterclockwise, IsLargeArc = isLargeArc });
            pathFigure.Segments.Add(new LineSegment { Point = new Point(this.Radious, this.Radious) });
            pathGeometry.Figures.Add(pathFigure);

            Grid.SetRow(path, 1);
            this.grid.Children.Add(path);

            //
            //下一个圆弧从这个圆弧结束的地方开始画起
            //
            _arcStartPoint = arcEndPoint;
        }

        private void DrawSector()
        {
            int count = this.grid.Children.Count;
            for (int i = 0; i < count; i++)
            {
                if (this.grid.Children[i] is Path)
                {
                    this.grid.Children.Remove((Path)this.grid.Children[i]);
                    count--;
                    i--;
                }
            }
            //
            //从圆的最右端开始画起
            //
            _arcStartPoint = new Point();
            _arcStartPoint.X = this.Radious * 2;
            _arcStartPoint.Y = this.Radious;
            _angle = 0;

            foreach (var item in _infoList)
            {
                this.DrawArc(item.Value, item.Color);
            }
        }

        private Point CalulateArcEndPoint(double value, double totalValue, out bool isLargeArc)
        {
            double angle = 0;
            if (value < totalValue)
            {
                angle = value / totalValue * 2 * Math.PI;
            }
            else
            {
                angle = Math.PI * 2 - 0.001;
            }

            isLargeArc = angle > Math.PI;

            double tempX = this.Radious * Math.Cos(angle + _angle);
            double tempY = this.Radious * Math.Sin(angle + _angle);

            //
            //笛卡尔坐标转换为以左上角为原点的坐标
            //
            double x = tempX + this.Radious;
            double y = this.Radious - tempY;

            _angle += angle;

            return new Point(x, y);
        }

        private void InitInfoList(IEnumerable itemsSource, out double totalValue)
        {
            List<Info> list = new List<Info>();

            totalValue = 0;

            if (this.ItemsSource != null)
            {
                foreach (var item in this.ItemsSource)
                {
                    Info info = new Info();

                    Type type = item.GetType();
                    totalValue += (Double)type.GetProperty(this.DependentPath).GetValue(item, null);

                    info.Value = (Double)type.GetProperty(this.DependentPath).GetValue(item, null);
                    info.Color = new SolidColorBrush((Color)type.GetProperty(this.ColorPath).GetValue(item, null));
                    info.Legend = (String)type.GetProperty(this.IndependentPath).GetValue(item, null);

                    list.Add(info);
                }
            }
            this.InfoList = list;
        }

        #region 属性

        internal List<Info> _infoList = new List<Info>();

        internal List<Info> InfoList
        {
            get { return _infoList; }
            set
            {
                _infoList = value;
            }
        }

        /// <summary>
        /// 标题
        /// </summary>
        public String ChartTitle
        {
            get { return (String)GetValue(ChartTitleProperty); }
            set
            {
                SetValue(ChartTitleProperty, value);
            }
        }

        public static readonly DependencyProperty ChartTitleProperty =
            DependencyProperty.Register("ChartTitle", typeof(String), typeof(PieChart), new PropertyMetadata(""));


        /// <summary>
        /// 半径
        /// </summary>

        public double Radious
        {
            get { return (double)GetValue(RadiousProperty); }
            set { SetValue(RadiousProperty, value); }
        }

        public static readonly DependencyProperty RadiousProperty =
            DependencyProperty.Register("Radious", typeof(double), typeof(PieChart), new PropertyMetadata(100d));


        /// <summary>
        /// 数据
        /// </summary>
        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set
            {
                SetValue(ItemsSourceProperty, value);
            }
        }

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(PieChart), new PropertyMetadata(new PropertyChangedCallback(ItemsSourcePropertyChanged)));

        private static void ItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as PieChart).Refresh();
        }

        public String IndependentPath
        {
            get { return (String)GetValue(IndependentPathProperty); }
            set { SetValue(IndependentPathProperty, value); }
        }

        public static readonly DependencyProperty IndependentPathProperty =
            DependencyProperty.Register("IndependentPath", typeof(String), typeof(PieChart), new PropertyMetadata(""));

        public String DependentPath
        {
            get { return (String)GetValue(DependentPathProperty); }
            set { SetValue(DependentPathProperty, value); }
        }

        public static readonly DependencyProperty DependentPathProperty =
            DependencyProperty.Register("DependentPath", typeof(String), typeof(PieChart), new PropertyMetadata(""));

        public String ColorPath
        {
            get { return (String)GetValue(ColorPathProperty); }
            set { SetValue(ColorPathProperty, value); }
        }

        public static readonly DependencyProperty ColorPathProperty =
            DependencyProperty.Register("ColorPath", typeof(String), typeof(PieChart), new PropertyMetadata(""));

        #endregion

    }

    internal class Info
    {
        public double Value { get; set; }

        public SolidColorBrush Color { get; set; }

        public String Legend { get; set; }
    }
}
